﻿//
// Author yuans
// Email: yyf9989@hotmail.com
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing ;

namespace XDesigner.AppFramework.WinForms
{
    public class DomTreeViewControler : IDisposable
    {
        public DomTreeViewControler()
        {
            CreateHandlers();
        }

        public DomTreeViewControler(TreeView tvw)
        {
            CreateHandlers();
            this.TreeView = tvw;
        }

        private TreeView _TreeView = null;

        public TreeView TreeView
        {
            get 
            {
                return _TreeView; 
            }
            set
            {
                if (_TreeView != value)
                {
                    if (_TreeView != null)
                    {
                        // release event handler
                        _TreeView.AfterExpand -= this._AfterExpand;
                        _TreeView.AfterSelect -= this._AfterSelect;
                        _TreeView.AfterCheck -= this._AfterCheck;
                    }
                    _TreeView = value;
                    if (_TreeView != null)
                    {
                        // bind event handler
                        _TreeView.AfterExpand += this._AfterExpand;
                        _TreeView.AfterSelect += this._AfterSelect;
                        _TreeView.AfterCheck += this._AfterCheck ;
                    }
                }
            }
        }

        private TreeViewEventHandler _AfterExpand = null;
        public event TreeViewEventHandler AfterExpand = null;

        private TreeViewEventHandler _AfterSelect = null;
        public event TreeViewEventHandler AfterSelect = null;

        private TreeViewEventHandler _AfterCheck = null;
        public event TreeViewEventHandler AfterCheck = null;

        /// <summary>
        /// Create treeview event handler
        /// </summary>
        private void CreateHandlers()
        {
            _AfterExpand = delegate(object sender, TreeViewEventArgs args)
                {
                    TreeView tvw = args.Node.TreeView;
                    CheckDynamicLoad(args.Node , true );
                    if (AfterExpand != null)
                    {
                        AfterExpand(sender, args);
                    }
                };
            _AfterSelect = delegate(object sender, TreeViewEventArgs args)
                {
                    TreeView tvw = args.Node.TreeView;
                    CheckDynamicLoad(args.Node, true);
                    if (AfterSelect != null)
                    {
                        AfterSelect(sender, args);
                    }
                };
            _AfterCheck = delegate(object sender, TreeViewEventArgs args)
                {
                    if (_SetChecking)
                        return;
                    _SetChecking = true;
                    CheckDynamicLoad(args.Node, true);
                    SetChildCheckState(args.Node);
                    if (args.Node.Checked)
                    {
                        TreeNode parentNode = args.Node.Parent;
                        while (parentNode != null)
                        {
                            parentNode.Checked = true;
                            parentNode = parentNode.Parent;
                        }
                    }
                    else
                    {
                        TreeNode parentNode = args.Node.Parent;
                        while (parentNode != null)
                        {
                            bool find = false;
                            foreach (TreeNode node2 in parentNode.Nodes)
                            {
                                if (node2.Checked)
                                {
                                    parentNode.Checked = true;
                                    find = true;
                                    break;
                                }
                            }
                            if (find == false)
                            {
                                parentNode.Checked = false;
                            }
                            parentNode = parentNode.Parent;
                        }
                    }

                    if (AfterCheck != null)
                    {
                        AfterCheck(sender, args);
                    }
                    _SetChecking = false;
                };
        }//private void CreateHandlers()

        private bool _SetChecking = false;

        private void SetChildCheckState(TreeNode rootNode )
        {
            if ( rootNode.Checked )
            {
                CheckDynamicLoad(rootNode , true );
            }
            foreach (TreeNode node in rootNode.Nodes)
            {
                node.Checked = rootNode.Checked ;
            }
        }

        private void CheckDynamicLoad(TreeNode node, bool useUpdate)
        {
            if (this.SupportDynamicLoad)
            {
                TreeNode node2 = node.FirstNode;
                if (node2 != null && node2.Tag == LoadingFlag)
                {
                    node.Nodes.Remove(node2);
                    if (useUpdate)
                    {
                        IList list = this.Provider.OnGetChildInstances(node.Tag);
                        if (list != null && list.Count > 10)
                        {
                            this.TreeView.BeginUpdate();
                            RefreshChildNodes(node, false);
                            this.TreeView.EndUpdate();
                            return;
                        }
                    }
                    RefreshChildNodes(node, false);
                }//if
            }//if
        }

        private ArrayList _RootInstances = new ArrayList();
        [System.ComponentModel.Browsable( false )]
        public ArrayList RootInstances
        {
            get
            {
                return _RootInstances; 
            }
            set
            {
                _RootInstances = value; 
            }
        }

        [System.ComponentModel.Browsable(false)]
        public object RootInstance
        {
            get
            {
                if (_RootInstances == null || _RootInstances.Count == 0)
                    return null;
                else
                    return _RootInstances[0];
            }
            set
            {
                if (_RootInstances == null)
                {
                    _RootInstances = new ArrayList();
                }
                else
                {
                    _RootInstances.Clear();
                }
                if( value != null )
                {
                    _RootInstances.Add(value);
                }
            }
        }

        private DomTreeProvider _Provider = new DomTreeProvider();
        [System.ComponentModel.Browsable( false )]
        public DomTreeProvider Provider
        {
            get
            {
                if (_Provider != null)
                {
                    _Provider.BindControl = this.TreeView ;
                }
                return _Provider; 
            }
            set
            {
                _Provider = value; 
            }
        }

        private bool _SupportDynamicLoad = false;

        public bool SupportDynamicLoad
        {
            get
            {
                return _SupportDynamicLoad;
            }
            set
            {
                _SupportDynamicLoad = value;
            }
        }

        private object LoadingFlag = new object();


        private void CheckTreeViewControl()
        {
            if (this.TreeView == null)
            {
                throw new InvalidOperationException("TreeView is null");
            }
        }

        public bool RemoveNode(TreeNode node)
        {
            CheckTreeViewControl();
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            TreeNode parentNode = node.Parent;
            if (parentNode != null)
            {
                IList list = this.Provider.OnGetChildInstances(parentNode.Tag);
                if (list != null)
                {
                    list.Remove(node.Tag);
                    node.Remove();
                    return true;
                }
            }
            return false;
        }

        public bool CanMoveUp(TreeNode node)
        {
            CheckTreeViewControl();
            return node.PrevNode != null ;
        }

        public bool MoveUp(TreeNode node)
        {
            CheckTreeViewControl();
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            TreeNode parentNode = node.Parent;
            if (parentNode != null)
            {
                int index = parentNode.Nodes.IndexOf(node);
                if (index > 1)
                {
                    object parentInstance = parentNode.Tag ;
                    IList childList = this.Provider.OnGetChildInstances(parentInstance);
                    int index2 = childList.IndexOf(node.Tag);
                    if (index2 != index)
                    {
                        return false;
                    }
                    // update DOM
                    childList.RemoveAt(index);
                    childList.Insert(index - 1, node.Tag);
                    // update view
                    TreeNode selNode = this.SelectedNode;
                    parentNode.Nodes.RemoveAt(index);
                    parentNode.Nodes.Insert(index - 1, node);
                    this.SelectedNode = selNode;
                    return true;
                }
            }
            return false;
        }

        public bool CanMoveDown(TreeNode node)
        {
            CheckTreeViewControl();
            return node.NextNode != null;
        }

        public bool MoveDown(TreeNode node)
        {
            CheckTreeViewControl();
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            TreeNode parentNode = node.Parent;
            if (parentNode != null)
            {
                int index = parentNode.Nodes.IndexOf(node);
                if (index < parentNode.Nodes.Count -1 )
                {
                    object parentInstance = parentNode.Tag;
                    IList childList = this.Provider.OnGetChildInstances(parentInstance);
                    int index2 = childList.IndexOf(node.Tag);
                    if (index2 != index)
                    {
                        return false;
                    }
                    // update DOM
                    childList.RemoveAt(index);
                    childList.Insert(index + 1, node.Tag);
                    // update view
                    TreeNode selNode = this.SelectedNode;
                    parentNode.Nodes.RemoveAt(index);
                    parentNode.Nodes.Insert(index + 1, node);
                    this.SelectedNode = selNode;
                    return true;
                }
            }
            return false;
        }

        public bool ChangeParent(object instance, object newParentInstance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }
            bool result = false;
            TreeNode node = GetNodeFast(instance);
            if (node == null)
            {
                throw new Exception("Not find node");
            }
            if (node.Parent != null)
            {
                object oldParentInstance = node.Parent.Tag;
                IList list = this.Provider.OnGetChildInstances(oldParentInstance);
                if (list.Contains(instance))
                {
                    list.Remove(instance);
                    result = true;
                }
            }
            node.Remove();
            
            if (newParentInstance != null)
            {
                IList list = this.Provider.OnGetChildInstances(newParentInstance);
                if (list.Contains(instance) == false)
                {
                    list.Add(instance);
                }
                TreeNode newParentNode = GetNode(newParentInstance);
                if (newParentNode != null)
                {
                    this.CheckDynamicLoad(newParentNode, true);
                    newParentNode.Nodes.Add(node);
                }
            }
            return result;
        }

        public void RefreshView()
        {
            CheckTreeViewControl();
            this.TreeView.BeginUpdate();
            this.TreeView.Nodes.Clear();
            if (this.RootInstances != null)
            {
                foreach (object obj in this.RootInstances)
                {
                    TreeNode rootNode = new TreeNode();
                    rootNode.Tag = obj ;
                    if (this.SupportDynamicLoad)
                    {
                        RefreshSingleNode(rootNode);
                         
                        //RefreshChildNodes(rootNode, false);
                    }
                    else
                    {
                        RefreshNode(rootNode, true);
                    }
                    this.TreeView.Nodes.Add(rootNode);
                }
            }
            this.TreeView.EndUpdate();
        }

        public void RefreshNode(TreeNode node, bool deeply)
        {
            CheckTreeViewControl();
            RefreshSingleNode(node );
            if (deeply)
            {
                RefreshChildNodes(node, deeply);
            }//if
        }

        public void RefreshChildNodes(TreeNode rootNode, bool deeply)
        {
            CheckTreeViewControl();
            object parentInstance = rootNode.Tag;
            IList childInstances = this.Provider.OnGetChildInstances(parentInstance);
            if (childInstances == null || childInstances.Count == 0 )
            {
                if (rootNode.Nodes.Count > 0)
                {
                    rootNode.Nodes.Clear();
                }
            }
            else
            {
                int index = 0;
                TreeNodeCollection nodes = rootNode.Nodes;
                foreach (object childInstance in childInstances)
                {
                    TreeNode childNode = null;
                    if (index < nodes.Count)
                    {
                        childNode = nodes[index];
                        if (childNode.Tag != childInstance)
                        {
                            for (int iCount = index + 1; iCount < nodes.Count; iCount++)
                            {
                                if (nodes[iCount].Tag == childInstance)
                                {
                                    childNode = nodes[iCount];
                                    nodes.RemoveAt(iCount);
                                    nodes.Insert(index, childNode);
                                    break;
                                }
                            }
                        }
                        if (childNode.Tag != childInstance)
                        {
                            childNode = new TreeNode();
                            childNode.Tag = childInstance;
                            RefreshNode(childNode, deeply);
                            nodes.Insert(index, childNode);
                        }
                        else
                        {
                            RefreshNode(childNode, deeply);
                        }
                    }
                    else
                    {
                        childNode = new TreeNode();
                        childNode.Tag = childInstance;
                        RefreshNode(childNode, deeply);
                        nodes.Add(childNode);
                        //nodes.Insert(index, childNode);
                    }
                    //RefreshNode(childNode, deeply);
                    index++;
                }//foreach
                if (nodes.Count > index )
                {
                    for (int iCount = nodes.Count - 1; iCount >= index; iCount--)
                    {
                        nodes.RemoveAt(iCount);
                    }
                }
            }//else
        }

        private ImageContainer _ImageList = new ImageContainer();

        public void RefreshSingleNode(TreeNode node )
        {
            CheckTreeViewControl();
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            object instance = node.Tag;
            object parentInstance = null;
            if (node.Parent != null)
            {
                parentInstance = node.Parent.Tag;
            }
            DomTreeEventArgs args = this.Provider.OnGetNodeStates(parentInstance, instance);
            if (args.Cancel == false )
            {
                if (node.Text != args.Text)
                {
                    node.Text = args.Text;
                }
                node.Tag = instance;
                if (node.ImageIndex != args.ImageIndex)
                {
                    node.ImageIndex = args.ImageIndex;
                }
                if (args.Image != null)
                {
                    if (this.TreeView.ImageList != null)
                    {
                        int index = _ImageList.GetImageIndex(args.Image);
                        if (index < 0)
                        {
                            this.TreeView.ImageList.Images.Add(args.Image);
                            index = this.TreeView.ImageList.Images.Count - 1;
                            _ImageList.SetImageIndex(args.Image , index );
                        }
                        node.ImageIndex = index;
                        node.SelectedImageIndex = index;
                    }
                }
                if (this.SupportDynamicLoad && args.HasChildInstances)
                {
                    TreeNode node2 = new TreeNode("Loading");
                    node2.Tag = LoadingFlag;
                    if (node.IsExpanded)
                    {
                        node.Collapse();
                    }
                    node.Nodes.Clear();
                    node.Nodes.Add(node2);
                    node.Collapse();
                }
            }
        }

        public TreeNode GetNodeFast(object instance)
        {
            return InnerGetNode(this.Nodes, instance);
        }

        public TreeNode GetNode(object instance )
        {
            if (instance == null)
            {
                return null;
            }
            CheckTreeViewControl();
            if (this.SupportDynamicLoad)
            {
                ArrayList list = GetParentList(instance);
                if (list.Count == 0)
                {
                    return InnerGetNode(this.Nodes, instance);
                }
                list.Reverse();
                list.Add(instance);
                TreeNode firstNode = InnerGetNode(this.Nodes, list[0]);
                list.RemoveAt(0);
                while (list.Count > 0)
                {
                    CheckDynamicLoad(firstNode , true );
                    object childInstance = list[0];
                    bool find = false;
                    foreach (TreeNode node in firstNode.Nodes)
                    {
                        if (node.Tag == childInstance)
                        {
                            if (childInstance == instance )
                            {
                                return node;
                            }
                            firstNode = node;
                            list.RemoveAt(0);
                            find = true;
                            break;
                        }
                    }//foreach
                    if (find == false)
                    {
                        return null;
                    }
                }//while
                return null;
            }
            else
            {
                return InnerGetNode(this.Nodes, instance);
            }
        }

        private TreeNode InnerGetNode(TreeNodeCollection nodes, object instance)
        {
            foreach (TreeNode node in nodes)
            {
                if (node.Tag == instance)
                {
                    return node;
                }
                TreeNode node2 = InnerGetNode(node.Nodes, instance);
                if (node2 != null)
                {
                    return node2;
                }
            }
            return null;
        }

        public object GetParentInstance(object instance)
        {
            TreeNode node = GetNode(instance);
            if (node != null && node.Parent != null)
            {
                return node.Parent.Tag;
            }
            return null;
        }

        public virtual object SelectedValue
        {
            get
            {
                CheckTreeViewControl();
                if (this.SelectedNode == null)
                {
                    return null;
                }
                else
                {
                    return this.SelectedNode.Tag;
                }
            }
            set
            {
                CheckTreeViewControl();
                if (value == null)
                {
                    return;
                }

                TreeNode node = this.GetNode(value);
                if (node != null)
                {
                    this.SelectedNode = node;
                }
            }
        }

        public TreeNode SelectedNode
        {
            get
            {
                CheckTreeViewControl();
                return this.TreeView.SelectedNode;
            }
            set
            {
                CheckTreeViewControl();
                this.TreeView.SelectedNode = value;
            }
        }

        [System.ComponentModel.Browsable( false )]
        public TreeNode[] CheckedNodes
        {
            get
            {
                CheckTreeViewControl();
                List<TreeNode> list = new List<TreeNode>();
                EnumerateNode(delegate(object sender, TreeViewCancelEventArgs args) 
                    {
                        if (args.Node.Checked)
                        {
                            list.Add(args.Node);
                        }
                    });
                return list.ToArray();
            }
        }

        [System.ComponentModel.Browsable( false )]
        public IList CheckedValues
        {
            get
            {
                CheckTreeViewControl();
                ArrayList list = new ArrayList();

                EnumerateNode(delegate(object sender, TreeViewCancelEventArgs args)
                    {
                        if (args.Node.Checked && args.Node.Tag != null )
                        {
                            list.Add(args.Node.Tag);
                        }
                    });
                return list.ToArray();
            }
            set
            {
                CheckTreeViewControl();
                _SetChecking = true;
                ArrayList tempList = null;
                if (value != null && value.Count > 0)
                {
                    tempList = new ArrayList(value);
                }
                //this.TreeView.BeginUpdate();
                TreeNode firstCheckedNode = null;
                EnumerateNode(delegate(object sender, TreeViewCancelEventArgs args) 
                    {
                        if (tempList != null && tempList.Count > 0 )
                        {
                            bool bolchecked = tempList.Contains( args.Node.Tag );
                            if (args.Node.Checked != bolchecked)
                            {
                                args.Node.Checked = bolchecked;
                            }
                            if (bolchecked)
                            {
                                tempList.Remove(args.Node.Tag);
                                if (firstCheckedNode == null)
                                {
                                    firstCheckedNode = args.Node;
                                }
                            }
                        }
                        else
                        {
                            if (args.Node.Checked)
                            {
                                args.Node.Checked = false;
                            }
                        }
                    });
                if (tempList  != null && tempList.Count > 0 )
                {
                    foreach (object obj in tempList )
                    {
                        TreeNode node = GetNode(obj);
                        if (node != null)
                        {
                            if (firstCheckedNode == null)
                            {
                                firstCheckedNode = node;
                            }
                            while (node != null)
                            {
                                if (node.Checked == false)
                                {
                                    node.Checked = true;
                                }
                                node = node.Parent;
                            }
                        }
                    }//foreach
                }//if
                if (firstCheckedNode != null)
                {
                    firstCheckedNode.EnsureVisible();
                    this.TreeView.SelectedNode = firstCheckedNode;
                }
                //this.TreeView.EndUpdate();
                _SetChecking = false;
            }
        }

        private System.Collections.ArrayList GetParentList(object instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }
            ArrayList list = new ArrayList();
            object parent = instance;
            while (parent != null)
            {
                parent = this.Provider.OnGetParentInstance(parent);
                if (parent == null)
                {
                    break;
                }
                list.Add(parent);
            }
            return list;
        }

        [System.ComponentModel.Browsable( false )]
        public TreeNodeCollection Nodes
        {
            get
            {
                CheckTreeViewControl();
                return this.TreeView.Nodes;
            }
        }

        public void Focus()
        {
            CheckTreeViewControl();
            this.TreeView.Focus();
        }

        public void EnumerateNode( TreeViewCancelEventHandler callBack)
        {
            if (callBack == null)
            {
                throw new ArgumentNullException("callBack");
            }
            InnerEnumerateNode(this.Nodes, callBack);
        }

        private bool InnerEnumerateNode( TreeNodeCollection nodes , TreeViewCancelEventHandler callBack)
        {
            foreach (TreeNode node in nodes)
            {
                TreeViewCancelEventArgs args = new TreeViewCancelEventArgs(
                    node, 
                    false, 
                    TreeViewAction.Unknown);
                callBack(this, args);
                if (args.Cancel)
                {
                    return false;
                }
                //CheckDynamicLoad(node);
                if (InnerEnumerateNode(node.Nodes, callBack) == false)
                {
                    return false;
                }
            }
            return true;
        }


        #region IDisposable 成员

        public void Dispose()
        {
            _ImageList.Dispose();
        }

        #endregion
    }//public class DomTreeViewControler

    
}
